﻿#include "recordsetdlg.h"
#include "QDateTime"
#include <QCheckBox>
#include <QImage>
#include <QLabel>
#include <QLineEdit>
#include <QSlider>
#include "EagleDeviceMgr.h"
#include "EagleApi.h"
#include "qdisplaywidget.h"
#include "QMessageBox"
#include "qevent.h"
#include "QTimer"
#include "QFileDialog"
#include <thread>
#include <future>
#include "ConfigFile.h"
#include <vector>
#include "common.h"
#include "EagleMainFrame.h"
#include <tuple>
#include <functional>
#include "QtConcurrentRun"

recordSetDlg::recordSetDlg(ConfigExportReplayContext* ctx,QWidget *parent)
	: QDialog(parent)
	, m_Repctx(ctx)
{
	ui.setupUi(this);

	ui.tabWidget->setCurrentIndex(0);
	QDateTime dt = QDateTime::fromTime_t(ctx->record_time);
	QString strTaskNam = QString::fromWCharArray(ctx->task_name.c_str());
	ui.label_tskNam->setText(QString("%1 - %2").arg(strTaskNam)
		.arg(dt.toString("yy/MM/dd hh:mm:ss")));
	GridLFm = new QGridLayout(ui.scrollFrame);  // 帧号方式
	GridLTm = new QGridLayout(ui.scrollTime);   // 时间方式
	
	this->setMaximumSize(712, 524);
	this->setMinimumSize(712, 524);
	
	if (ctx->export_or_replay != CONFIG_TO_EXPORT)
	{
		ui.widget_exPort->hide();  // 导出格式 和 导出目录 [11/2/2016 ejitec]
	}
	else
	{
		setWindowTitle(tr("导出参数设置"));
		ui.tabWidget->setTabText(ui.tabWidget->indexOf(ui.tab_time), tr("按时间导出"));
		ui.tabWidget->setTabText(ui.tabWidget->indexOf(ui.tab_frame), tr("按帧号导出"));
		ui.cmbType->clear();
		ui.cmbType->addItems(EagleConfigFile::getInstance()->export_types);
		ui.lineEdit_Path->setText(EagleConfigFile::getInstance()->last_export_path);
		ui.pushButton_Sel->setAutoDefault(false);
		ui.pushButton->setAutoDefault(false);
		ui.pushButton_2->setAutoDefault(false);
	}

	connect(ui.pushButton_Sel, &QPushButton::clicked, this, [=]()
	{
		QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"),
			qApp->applicationDirPath(),
			QFileDialog::ShowDirsOnly
			| QFileDialog::DontResolveSymlinks);

		ui.lineEdit_Path->setText(dir);

	});

	for (std::vector<ExportReplayContextCcd>::iterator it = ctx->ccd_context.begin(); it != ctx->ccd_context.end(); it++)
	{
		try{

			ccdRecordFrameSet* ccdRecF = new ccdRecordFrameSet(*it, ctx->task_name, ctx->record_time, this);
			if (ccdRecF)
			{
				int nRow = 0;
				if (_frameSetList.size() != 0)
				{
					nRow = GridLFm->rowCount();
				}
				GridLFm->addWidget(ccdRecF, nRow, 0, Qt::AlignTop);
				//GridLFm->setRowMinimumHeight(nRow, 100);
				//GridLFm->setRowStretch(nRow, 10);
				_frameSetList << ccdRecF;
				
				QFrame*line = new QFrame(ui.scrollFrame);
				line->setFrameShape(QFrame::HLine);
				line->setFrameShadow(QFrame::Sunken);
				GridLFm->addWidget(line,GridLFm->rowCount(), 0, 1, GridLFm->columnCount(), Qt::AlignTop);
			}

			ccdRecordTimeSet* ccdRecT = new ccdRecordTimeSet(*it, ctx->task_name, ctx->record_time, this);
			if (ccdRecT)
			{
				int nRow = 0;
				if (_timeSetList.size() != 0)
				{
					nRow = GridLTm->rowCount();
				}
				GridLTm->addWidget(ccdRecT, nRow, 0, Qt::AlignTop);
				//GridLTm->setRowMinimumHeight(nRow, 100);
				GridLTm->setRowStretch(nRow, 10);
				_timeSetList << ccdRecT;
				
				QFrame*line = new QFrame(ui.scrollTime);
				line->setFrameShape(QFrame::HLine);
				line->setFrameShadow(QFrame::Sunken);
				GridLTm->addWidget(line, GridLFm->rowCount(), 0, 1, GridLTm->columnCount(), Qt::AlignTop);
			}
		}
		catch (std::runtime_error &){
			return;
		}
	}
}

recordSetDlg::~recordSetDlg()
{
}


bool recordSetDlg::toCheck() 
{
	bool bOK = true;
	QVector<checkPageWidget*> cur = ui.tabWidget->currentIndex() == 0 ? _frameSetList : _timeSetList;

	for (auto it : cur)
	{
		if (!it->isCheck())
		{
			continue;
		}
		if (!it->on_checkOK())
		{
			bOK = false;
			break;
		}
	}

	return bOK;
}

void recordSetDlg::on_setOK()
{
	bool bCheck = false;
	for (auto it : m_Repctx->ccd_context)
	{
		if (it.checked)
		{
			bCheck = true;
			break;
		}
	}

	if (!bCheck)
	{
		QMessageBox::warning(this, GetMessageBoxTitle(), tr("请至少选择一个相机"));

		return;
	}

	if (!toCheck())
	{
		return;
	}

	if (m_Repctx->export_or_replay != CONFIG_TO_EXPORT)
	{
		return accept();
	}

	m_Repctx->export_path = ui.lineEdit_Path->text();
	m_Repctx->export_type = ui.cmbType->currentIndex();
	if (m_Repctx->export_path.isEmpty())
	{
		QMessageBox::warning(this, GetMessageBoxTitle(), tr("请选择导出目录"));

		return;
	}

	EagleConfigFile::getInstance()->last_export_path = m_Repctx->export_path;
	EagleConfigFile::getInstance()->store();

	m_Repctx->index_or_time = ui.tabWidget->currentIndex();

	this->accept();
}

void recordSetDlg::on_tabChange(int n)
{
	m_Repctx->index_or_time = n;
}

int recordSetDlg::getCMD(MessageCmd& cmd, EagleData_CcdRecord* ccd_record)
{
	auto ccd_ctx_it = std::find_if(
		m_Repctx->ccd_context.begin(),
		m_Repctx->ccd_context.end(),
		[&](const ExportReplayContextCcd &ctxccd)
	{
		return ctxccd.ccd_index == ccd_record->id.ccd_serial
			&& ctxccd.device_id == ccd_record->id.device_id;
	});


	if (ccd_ctx_it == m_Repctx->ccd_context.end() || !ccd_ctx_it->checked)
	{
		ccd_record = ccd_record->next;
		return -1;
	}

	wcscpy(cmd.task_name, m_Repctx->task_name.c_str());
	cmd.replay_export_method = 0;
	cmd.device_id = ccd_record->id.device_id;
	cmd.ccd_serial = ccd_record->id.ccd_serial;
	cmd.line = ccd_record->line;
	cmd.column = ccd_record->column;
	cmd.color_depth = ccd_record->color_depth;
	cmd.frame_rate = 0;//NOT USE
	cmd.record_time = ccd_record->record_id.start_time;
	cmd.replay_export_method = m_Repctx->index_or_time;// for time replay
	cmd.frame_time_interval = ccd_ctx_it->time_interval;//NOT USE
	cmd.interval = ccd_ctx_it->interval;

	cmd.Replay.replay_start_index = ccd_ctx_it->start_frame_index;
	cmd.Replay.replay_end_index = ccd_ctx_it->end_frame_index;
	cmd.Export.export_decode_method = 0;  // 
	QString path = m_Repctx->export_path;
	if (!path.endsWith(QDir::separator()))
	{
		path.push_back(QDir::separator());
	}
	path += QString::fromStdWString(m_Repctx->task_name);
	path += QDateTime::fromTime_t(m_Repctx->record_time).toString("-yyyyMMdd_hhmmss");
	memset(cmd.Export.export_path, 0, sizeof(cmd.Export.export_path));
	path.toWCharArray(cmd.Export.export_path);
	// wcscpy
	cmd.Export.export_type = m_Repctx->export_type;
	cmd.Export.export_start_index = ccd_ctx_it->start_frame_index;//TODO
	cmd.Export.export_end_index = ccd_ctx_it->end_frame_index;

	return 0;
}


static void Decode(int device_id, int ccd_no, PIXEL_SAMPLING_TYPE type, unsigned char *dest, unsigned char *source, int& color_depth, int& column, int& line)
{
	DecodeRequestStruct request;
	request.needResize = true;
	request.muitiplier = 4;
	request.IsRgbSort = true;
	request.data_source_is_resized = false;
	request.original_color_depth = color_depth;
	request.original_column = column;
	request.original_line = line;
	request.original_real_color_depth = 0;
	request.LeftRightReverse = EagleConfigFile::getInstance()->GetDeviceCameraLeftRightReverse(device_id, ccd_no);
	request.UpDownReverse = EagleConfigFile::getInstance()->GetDeviceCameraUpDownReverse(device_id, ccd_no);

	QString decoder = global_decoder_name[type];

#ifdef CHENGGS_VERSION
	if (ccd_no == 3 && type == PixelSamplingGrey)
		decoder = "CHENGColor";
	else if (ccd_no == 4 && type == PixelSamplingGrey)
		decoder = "MonoDecoder";
#endif

	int rotated = DecoderPluginMgr::getInstance()->getDecoder(decoder.toStdWString())->Decode(
		dest,
		column * line * 3,
		source,
		color_depth,
		column,
		line,
		&request
		);
	DecoderPlugin::DecodedParam decoded_param(color_depth, column, line);
	DecoderPluginMgr::getInstance()->getDecoder(decoder.toStdWString())->GetDecodedParam(
		decoded_param, color_depth, column, line, &request);
}


QImage ccdRecordFrameSet::getPreviewImgByFm(int index, QSize img_size, QString& time)
{
	int head_size = HEAD_SIZE(_ccd->column, _ccd->line, _ccd->color_depth);
	int data_size = _ccd->column * _ccd->line * ((_ccd->color_depth + 7) / 8);
	char *data_buf = new char[data_size];
	char *head_buf = new char[head_size];
	int success = EagleData_ReadOneStoredFrame(_ccd->record_id, _ccd->id, index, data_buf, data_size, head_buf, head_size);
	if (success != 0)
	{
		delete[] data_buf;
		delete[] head_buf;
		/*throw std::runtime_error("Failed read frame data to preview.");*/
		return QImage();
	}
	FrameHead head;
	EagleData_AnalyzeFrameHead(head_buf, &head);
	time = QString("").sprintf("%02d:%02d:%02d.%03d", head.h, head.m, head.s, head.ms);

	unsigned char *image_buf = new unsigned char[_ccd->column * _ccd->line * 3];
	int color_depth = _ccd->color_depth;
	int column = _ccd->column;
	int line = _ccd->line;
	Decode(_ccd->id.device_id, _ccd->id.ccd_serial, _ccd->pixel_sampling_type, image_buf, (unsigned char *)data_buf, color_depth, column, line);

	QImage img(column, line, QImage::Format_RGB888);
	memcpy(img.bits(), image_buf, img.byteCount());
	delete[] data_buf;
	delete[] head_buf;
	delete[] image_buf;

	return img.scaled(img_size, Qt::IgnoreAspectRatio);
}

ccdRecordFrameSet::ccdRecordFrameSet(ExportReplayContextCcd& tCtx, wstring& strTskNam, time_t& dt, QWidget *parent /*= 0*/)
	:checkPageWidget(parent)
	, m_ctx(tCtx)
	, _preStartFram(-101)
	, _preEndFram(-101)
{
	ui.setupUi(this);
	this->setFixedHeight(140);
	_ccd = EagleDataMgr::GetInstance()->GetCcdRecord(strTskNam, dt, m_ctx.device_id, m_ctx.ccd_index);

	string start_time, end_time;
	wchar_t dev_name[32] = { '\0' };
	wchar_t ccd_name[32] = { '\0' };
	EagleControl_GetDeviceName(m_ctx.device_id, dev_name);
	EagleControl_GetCameraName(m_ctx.device_id, m_ctx.ccd_index, ccd_name);
	ui.checkBox_ccd->setText(QString("%1\n%2").arg(QString::fromWCharArray(dev_name)).arg(QString::fromWCharArray(ccd_name)));
	frame_index_max = (int(_ccd->frame_number) > 2) ? _ccd->frame_number - 1 : 1;

	ui.hSlider_start->setRange(0,frame_index_max);
	ui.spinBox_start->setRange(0, frame_index_max);
	
	ui.hSlider_end->setRange(0, frame_index_max);
	ui.spinBox_end->setRange(0, frame_index_max);
	
	ui.hSlider_start->setValue(0);
	ui.hSlider_end->setValue(frame_index_max);
	ui.checkBox_ccd->setChecked(true);
	ui.lineEdit_CZ->setText(QString::number(1));
	ui.lineEdit_fm1->setText(QString::number(0));
	ui.lineEdit_fm2->setText(QString::number(frame_index_max));
	QIntValidator *int_validator = new QIntValidator(0, frame_index_max);
	ui.lineEdit_fm1->setValidator(int_validator);
	ui.lineEdit_fm2->setValidator(int_validator);
	ui.lineEdit_CZ->setValidator(int_validator);
	m_ctx.interval = 1;
	m_ctx.start_frame_index = 0;
	m_ctx.end_frame_index = frame_index_max;

	connect(ui.lineEdit_fm1, &QLineEdit::editingFinished, [=]()
	{
		bool bOK = false;
		int nValue = ui.lineEdit_fm1->text().toInt(&bOK);
		ui.hSlider_start->setValue(nValue);
		
	});

	connect(ui.lineEdit_fm2, &QLineEdit::editingFinished, [=]()
	{
		bool bOK = false;
		int nValue = ui.lineEdit_fm2->text().toInt(&bOK);
		ui.hSlider_end->setValue(nValue);
	});

	connect(ui.hSlider_start, &QSlider::valueChanged, this, [=](int index)
	{
		if (_preStartFram == index && _preStartFram != 0)
		{
			qDebug() << "hSlider_start:" << index << "the same as:" << _preStartFram;
			return;
		}

		if (index > ui.hSlider_end->value())
		{
			QMessageBox::warning(this, GetMessageBoxTitle(), tr("开始帧大于结束帧"));
			ui.hSlider_start->setValue(_preStartFram);
			ui.lineEdit_fm1->setText(QString::number(_preStartFram));
			return;
		}

		QString strText;
		QImage img = getPreviewImgByFm(index, ui.label_ImageS->size(), strText);
		if (!img.isNull())
			ui.label_ImageS->setPixmap(QPixmap::fromImage(img));
		ui.lineEdit_tm1->setText(strText);
		_preStartFram = index;
		ui.lineEdit_fm1->setText(QString::number(index));
		m_ctx.start_frame_index = _preStartFram;
		ui.label_ImageS->update();

	});

	connect(ui.hSlider_end, &QSlider::valueChanged, this, [this](int index)
	{
		if (_preEndFram == index)
		{
			qDebug() << "hSlider_end:" <<index << " the same as:" << _preEndFram;
			return;
		}

		if (index < ui.hSlider_start->value())
		{
			QMessageBox::warning(this, GetMessageBoxTitle(), tr("结束帧小于开始帧"));
			ui.hSlider_end->setValue(_preEndFram);
			ui.lineEdit_fm2->setText(QString::number(_preEndFram));
			return;
		}

 		QString strText;
		QImage img = getPreviewImgByFm(index, ui.label_ImageE->size(), strText);
		if (!img.isNull())
			ui.label_ImageE->setPixmap(QPixmap::fromImage(img));
		ui.lineEdit_tm2->setText(strText);
		_preEndFram = index;
		ui.lineEdit_fm2->setText(QString::number(index));
		m_ctx.end_frame_index = _preEndFram;
		ui.label_ImageE->update();
	});
}

void ccdRecordFrameSet::on_Check(int n)
{
	bool bCheck = (n == Qt::Checked);
	m_ctx.checked = ui.checkBox_ccd->isChecked();
	ui.hSlider_end->setEnabled(bCheck);
	ui.hSlider_start->setEnabled(bCheck);
	ui.spinBox_end->setEnabled(bCheck);
	ui.spinBox_start->setEnabled(bCheck);
	ui.lineEdit_CZ->setEnabled(bCheck);
	ui.lineEdit_fm1->setEnabled(bCheck);
	ui.lineEdit_fm2->setEnabled(bCheck);
}

bool ccdRecordFrameSet::on_checkOK()
{
	//qDebug() << *ui.label_ImageE->pixmap() << *ui.label_ImageS->pixmap();
	if (!ui.label_ImageE->pixmap() || !ui.label_ImageS->pixmap())
	{
		QMessageBox::warning(this, GetMessageBoxTitle(), tr("无效起/止帧"));
		return false;
	}

	int start_index_num = ui.lineEdit_fm1->text().toInt();
	int stop_index_num = ui.lineEdit_fm2->text().toInt();
	if (start_index_num < 0 || stop_index_num < 0 || start_index_num > stop_index_num)
	{
		QMessageBox::warning(this, GetMessageBoxTitle(), tr("非法起/止帧号"));
		return false;
	}

	if (ui.lineEdit_CZ->text().toInt() > (1 + stop_index_num - start_index_num))
	{
		QMessageBox::warning(this, GetMessageBoxTitle(), tr("非法抽帧间隔"));
		return false;
	}

	return true;
}

void ccdRecordFrameSet::on_freshEditValue()
{
	QLineEdit* cur = qobject_cast<QLineEdit*>(sender());

	if (cur->text().toInt() > (1 + ui.hSlider_end->value() - ui.hSlider_start->value()))
	{
		QMessageBox::warning(this, GetMessageBoxTitle(), tr("无效抽帧"));
		cur->setText(QString::number(1));
		return;
	}

	m_ctx.interval = cur->text().toInt();
}

void ccdRecordFrameSet::resizeEvent(QResizeEvent *event)
{
	QWidget::resizeEvent(event);
	//qDebug() << "ccdRecordFrameSet::resizeEvent:" << event->size() << event->oldSize();
}

void ccdRecordFrameSet::showEvent(QShowEvent *event)
{
	QTimer::singleShot(10, this, [=]()
	{
		QString strText;
		QImage img = getPreviewImgByFm(frame_index_max, ui.label_ImageE->size(), strText);
		if (!img.isNull())
		{
			ui.label_ImageE->setPixmap(QPixmap::fromImage(img));
			ui.lineEdit_tm2->setText(strText);
		}
			

		img = getPreviewImgByFm(0, ui.label_ImageS->size(), strText);
		if (!img.isNull())
		{
			ui.label_ImageS->setPixmap(QPixmap::fromImage(img));
			ui.lineEdit_tm1->setText(strText);
		}
			
	});
}


ccdRecordTimeSet::ccdRecordTimeSet(ExportReplayContextCcd& tCtx, wstring& strTskNam, time_t& dt, QWidget *parent /*= 0*/)
:checkPageWidget(parent)
, m_ctx(tCtx)
{
	ui.setupUi(this);
	this->setFixedHeight(140);
	_ccd = EagleDataMgr::GetInstance()->GetCcdRecord(strTskNam, dt, m_ctx.device_id, m_ctx.ccd_index);
	string start_time, end_time;
	wchar_t dev_name[32] = { '\0' };
	wchar_t ccd_name[32] = { '\0' };
	EagleControl_GetDeviceName(m_ctx.device_id, dev_name);
	EagleControl_GetCameraName(m_ctx.device_id, m_ctx.ccd_index, ccd_name);
	ui.checkBox_ccd->setText(QString("%1\n%2").arg(QString::fromWCharArray(dev_name)).arg(QString::fromWCharArray(ccd_name)));
	long frame_index_max = (int(_ccd->frame_number) > 2) ? _ccd->frame_number - 1 : 1;
	ui.checkBox_ccd->setChecked(true);
	std::wstring time_format = EagleConfigFile::getInstance()->time_decoder_format.toStdWString();
	unsigned long h = 0, m = 0, s = 0, ms = 0;
	GetRecordTimeInIndex(_ccd->record_id, _ccd->id, 0, _ccd->column, _ccd->line, _ccd->color_depth, time_format, &h, &m, &s, &ms);
	min = QTime(h, m, s, ms);
	start_time_ms = (h * 3600 + m * 60 + s) * 1000 + ms;
	
	GetRecordTimeInIndex(_ccd->record_id, _ccd->id, _ccd->frame_number - 1, _ccd->column, _ccd->line, _ccd->color_depth, time_format, &h, &m, &s, &ms);
	if (ms != 0)
		s += 1;
	max = QTime(h, m, s, ms);
	stop_time_ms = (h * 3600 + m * 60 + s) * 1000 + ms;
	
	ui.timeEdit_1->setTimeRange(min, max);
	ui.timeEdit_2->setTimeRange(min, max);
	ui.timeEdit_1->setTime(min);
	ui.timeEdit_2->setTime(max);
	ui.lineEdit_fm1->setText(QString::number(0));
	ui.lineEdit_fm2->setText(QString::number(frame_index_max));
	QIntValidator *int_validator = new QIntValidator(0, frame_index_max);
	ui.lineEdit_fm1->setValidator(int_validator);
	ui.lineEdit_fm2->setValidator(int_validator);

	connect(ui.timeEdit_1, &QTimeEdit::userTimeChanged, this, [=](QTime tm)
	{
		if (_preStartTm == tm)
		{
			return;
		}

		if (ui.timeEdit_1->time() > ui.timeEdit_2->time())
		{
			QMessageBox::warning(this, GetMessageBoxTitle(), tr("开始时间大于结束时间"));
			ui.timeEdit_1->setTime(_preStartTm);
			return;
		}

		int index;

		QImage image = getPreviewImgByTm(index, ui.label_ImageS->size(), tm.hour(), tm.minute(), tm.second());
		if (!image.isNull())
		{
			ui.label_ImageS->setPixmap(QPixmap::fromImage(image));
		}
		ui.lineEdit_fm1->setText(QString::number(index));
		_preStartTm = ui.timeEdit_1->time();
		m_ctx.start_frame_index = index;
	});

	connect(ui.timeEdit_2, &QTimeEdit::timeChanged, this, [this](QTime tm)
	{
		if (_preEndTm == tm)
		{
			return;
		}

		if (ui.timeEdit_2->time() < ui.timeEdit_1->time())
		{
			QMessageBox::warning(this, GetMessageBoxTitle(), tr("结束时间小于开始时间"));
			ui.timeEdit_2->setTime(_preEndTm);

			return;
		}

		int index;
		QImage image = getPreviewImgByTm(index, ui.label_ImageS->size(), tm.hour(), tm.minute(), tm.second());
		if (!image.isNull())
		{
			ui.label_ImageE->setPixmap(QPixmap::fromImage(image));
		}
		ui.lineEdit_fm2->setText(QString::number(index));
		_preEndTm = ui.timeEdit_2->time();
		m_ctx.end_frame_index = index;
	});

}

void ccdRecordTimeSet::on_Check(int n)
{
	bool bCheck = (n == Qt::Checked);
	m_ctx.checked = ui.checkBox_ccd->isChecked();
	ui.timeEdit_1->setEnabled(bCheck);
	ui.timeEdit_2->setEnabled(bCheck);
	ui.lineEdit_CZ->setEnabled(bCheck);
	ui.lineEdit_fm1->setEnabled(bCheck);
	ui.lineEdit_fm2->setEnabled(bCheck);
}

bool  ccdRecordTimeSet::on_checkOK()
{
	if (ui.label_ImageE->pixmap()->isNull() || ui.label_ImageS->pixmap()->isNull())
	{
		QMessageBox::warning(this, GetMessageBoxTitle(), tr("无效起/止帧"));
		return false;
	}

	if (ui.lineEdit_CZ->text().toInt() >= ui.lineEdit_fm2->text().toInt())
	{
		QMessageBox::warning(this, GetMessageBoxTitle(), tr("非法抽帧间隔"));
		return false;
	}

	return true;
}

void ccdRecordTimeSet::on_freshEditValue()
{
	QLineEdit* cur = qobject_cast<QLineEdit*>(sender());

	if (cur->text().toInt() >= ui.timeEdit_2->time().msec() - ui.timeEdit_1->time().msec())
	{
		QMessageBox::warning(this, GetMessageBoxTitle(), tr("无效抽帧"));
		cur->setText(QString::number(1));
		return;
	}

	m_ctx.interval = cur->text().toInt();
}

QImage ccdRecordTimeSet::getPreviewImgByTm(int& index, QSize img_size, int h, int m, int s)
{
	index = -1;

	std::wstring time_format = EagleConfigFile::getInstance()->time_decoder_format.toStdWString();
	//计算搜索时间
	unsigned int search_time = (h * 3600 + m * 60 + s) * 1000;

	// 计算一个大概索引值
	unsigned int Total = stop_time_ms - start_time_ms;
	if (Total == 0)
	{
		return QImage();		
	}
	
	unsigned long long Offset = search_time - start_time_ms;
	if (search_time <= start_time_ms)
		Offset = 0;
	index = (Offset * _ccd->frame_number) / Total;

	unsigned long ch = 0, cm = 0, cs = 0, cms = 0;
	bool success = GetRecordTimeInIndex(_ccd->record_id, _ccd->id, index, _ccd->column, _ccd->line, _ccd->color_depth, time_format, &ch, &cm, &cs, &cms);
	if (!success)
	{
		index = -1;
		
		return QImage();
	}

	bool searchDirection = false;

	unsigned int current_time = (ch * 3600 + cm * 60 + cs) * 1000 + cms;
	int nDelta = current_time - search_time;
	if (nDelta >= 0)
		searchDirection = false;
	else
		searchDirection = true;


	while (/*nDelta >= 0 && */index != 0 && index != (_ccd->frame_number - 1))
	{
		if (searchDirection)
			index++;
		else
			index--;
		success = GetRecordTimeInIndex(_ccd->record_id, _ccd->id, index, _ccd->column, _ccd->line, _ccd->color_depth, time_format, &ch, &cm, &cs, &cms);
		if (!success){
			index = -1;
			throw std::runtime_error("Failed read frame data to preview.");
			break;
		}
		current_time = (ch * 3600 + cm * 60 + cs) * 1000 + cms;
		nDelta = current_time - search_time;
		/*if (!searchDirection && nDelta >= 0)
		nDelta = 0 - nDelta;*/
		if (searchDirection && nDelta >= 0 || !searchDirection && nDelta <= 0)
			break;
	}
	if (s > cs)
	{
		++index;
	}
	if (index > (_ccd->frame_number - 1))
		index = _ccd->frame_number - 1;

_SUCCESS:

	int head_size = HEAD_SIZE(_ccd->column, _ccd->line, _ccd->color_depth);
	int data_size = _ccd->column * _ccd->line * ((_ccd->color_depth + 7) / 8);
	char *data_buf = new char[data_size];
	char *head_buf = new char[head_size];

	int data_success = EagleData_ReadOneStoredFrame(_ccd->record_id, _ccd->id, index, data_buf, data_size, head_buf, head_size);
	if (data_success != 0){
		delete[] data_buf;
		delete[] head_buf;
		index = -1;
		throw std::runtime_error("Failed read frame data to preview.");
	}
	unsigned char *image_buf = new unsigned char[_ccd->column * _ccd->line * 3];
	int color_depth = _ccd->color_depth;
	int column = _ccd->column;
	int line = _ccd->line;
	Decode(_ccd->id.device_id, _ccd->id.ccd_serial, _ccd->pixel_sampling_type, image_buf, (unsigned char *)data_buf, color_depth, column, line);
	
	QImage img(column, line, QImage::Format_RGB888);
	memcpy(img.bits(), image_buf, img.byteCount());
	QImage tmpImg = img.scaled(img_size, Qt::IgnoreAspectRatio,Qt::SmoothTransformation);

	delete[] data_buf;
	delete[] head_buf;
	delete[] image_buf;
	return tmpImg;
}

// 放大事件 会触发2次 
void ccdRecordTimeSet::resizeEvent(QResizeEvent *event)
{
	QWidget::resizeEvent(event);

//	qDebug() << "ccdRecordTimeSet::resizeEvent:" << event->size() << event->oldSize();
	
}

void ccdRecordTimeSet::showEvent(QShowEvent *event)
{
	QTimer::singleShot(10, this, [=]()
	{
		int index;
		QTime tm = min;
		QImage image = getPreviewImgByTm(index, ui.label_ImageS->size(), tm.hour(), tm.minute(), tm.second());
		if (!image.isNull())
			ui.label_ImageS->setPixmap(QPixmap::fromImage(image));

		tm = max;
		image = getPreviewImgByTm(index, ui.label_ImageS->size(), tm.hour(), tm.minute(), tm.second());
		if (!image.isNull())
			ui.label_ImageE->setPixmap(QPixmap::fromImage(image));
	});
}


//////////////////////////////////////////////////////////////////////////
// 批量导出功能  [11/7/2016 ejitec]
batchExport::batchExport(BatchExportContext& ctx, QWidget* parent)
:QDialog(parent)
, _ctx(ctx)
, post_event_mgr(this)
{
	ui.setupUi(this);

	QFont font("Consolas", 10, QFont::Medium);
	ui.currentExportRecord->setFont(font);
	ui.listw_exp->setSelectionMode(QAbstractItemView::ExtendedSelection);
	
	QVariant var;
	for (auto it : _ctx.remain_export_record)
	{
		QDateTime dt = QDateTime::fromTime_t(it->start_time);
		QListWidgetItem* item = new QListWidgetItem(QString::fromWCharArray(it->task_name)
			+ dt.toString("-yy/MM/dd hh:mm:ss"));
		var = QVariant::fromValue(it);
		item->setData(Qt::UserRole, var);
		ui.listw_exp->addItem(item);
	}
	
	ui.comboBox->clear();
	ui.comboBox->addItems(EagleConfigFile::getInstance()->export_types);
	ui.lineEditPath->setText(EagleConfigFile::getInstance()->last_export_path);

	connect(ui.btn_delAll, &QPushButton::clicked, this, [this]()
	{
		//ui.listw_exp->clear();

		_ctx.export_context_lock.lock();
		_ctx.cancel_export = true;
		_ctx.export_context_lock.unlock();
	});


	connect(ui.btn_delSel, &QPushButton::clicked, this, [this]()
	{
		for (auto it : ui.listw_exp->selectedItems())
		{
			EagleData_Record_Id* rec = it->data(Qt::UserRole).value<EagleData_Record_Id*>();
			_ctx.remain_export_record.erase(
				std::remove(_ctx.remain_export_record.begin(), _ctx.remain_export_record.end(), rec)
				, _ctx.remain_export_record.end());
			ui.listw_exp->takeItem(ui.listw_exp->currentRow());
		}
	});

	connect(ui.pushButton_Sel, &QPushButton::clicked, this, [this]()
	{
		QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"),
			qApp->applicationDirPath(),
			QFileDialog::ShowDirsOnly
			| QFileDialog::DontResolveSymlinks);

		ui.lineEditPath->setText(dir);
		EagleConfigFile::getInstance()->last_export_path = dir;
	});

	connect(ui.btn_start, &QPushButton::clicked, this, &batchExport::on_startBatchExp);
	ui.currentExportRecord->setText("Status Ready");
}

void batchExport::NotBlockingSleep(int ms)
{
	unsigned nTimes = ms / 10;
	do 
	{
		qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
		QThread::msleep(10);
	} while (--nTimes > 0);
	
}

void batchExport::StartBatchExportThread()
{
	qDebug() << "StartBatchExportThread starting ...";
	
	DISK_MOUNT_TYPE type = (DISK_MOUNT_TYPE)EagleConfigFile::getInstance()->disk_mount_type.toInt();
	int nRet = EagleData_CheckAndRemountFileSystem(0, type); // all device

	post_event_mgr.Post([this, nRet]()
	{
		ui.currentExportRecord->setText(QString("mounting disks complete %1").arg(nRet  == 0 ? "ok" : "failed"));
		ui.btn_delAll->setEnabled(true);
	});

	NotBlockingSleep(100);

	void* exporting_record = NULL;
	std::vector<std::tuple<int, int>> cmds;
	forever
	{
		cmds.clear();
		try
		{
			if (_ctx.remain_export_record.empty() || _ctx.cancel_export)
				break;
			_ctx.export_context_lock.lock();
			exporting_record = *_ctx.remain_export_record.begin();
		}
		catch (std::out_of_range)
		{
			_ctx.export_context_lock.unlock();
			break;
		}
		_ctx.remain_export_record.erase(_ctx.remain_export_record.begin());
		_ctx.export_context_lock.unlock();
		EagleData_Record_Id* record_id = (EagleData_Record_Id*)(exporting_record);  // 当前 导出记录
		qDebug() << "select record: " << record_id->start_time << ",task:" << QString::fromWCharArray(record_id->task_name);
		EagleData_Record *record = EagleDataMgr::GetInstance()->GetRecord(record_id);
		EagleData_CcdRecord *ccd_record = record->ccd_record_list;
		ccd_record = record->ccd_record_list;
		while (ccd_record != 0)
		{
			MessageCmd* ptcmd = new MessageCmd(GT_CMD_EXPORT_START);
			MessageCmd& cmd = *ptcmd;
			wcscpy(cmd.task_name, record_id->task_name);
			cmd.device_id = ccd_record->id.device_id;
			cmd.ccd_serial = ccd_record->id.ccd_serial;
			cmd.line = ccd_record->line;
			cmd.column = ccd_record->column;
			cmd.color_depth = ccd_record->color_depth;
			cmd.frame_rate = 0;//NOT USE
			cmd.record_time = ccd_record->record_id.start_time;
			cmd.replay_export_method = 0;// for time export
			cmd.Export.export_type = _ctx.export_type;

			QString ccd_export_path = _ctx.export_path;
			if (!ccd_export_path.endsWith(QDir::separator()))
			{
				ccd_export_path.append(QDir::separator());
			}

			ccd_export_path += QString::fromWCharArray(record_id->task_name);
			QDateTime dt = QDateTime::fromTime_t(record_id->start_time);
			ccd_export_path += dt.toString("-yyyyMMdd_hhmmss");
			ccd_export_path.toWCharArray(cmd.Export.export_path);
			//wcscpy(cmd.Export.export_path, ccd_export_path.toStdWString().c_str());
			cmd.Export.export_start_index = 0;//TODO
			cmd.Export.export_end_index = ccd_record->frame_number - 1;
			cmd.Export.export_decode_method = 0;//currently no use, set to 0
			cmd.interval = 1;

			QDisPlayWidget* curWnd = g_theApp->getPlayWndBy(ptcmd->device_id, ptcmd->ccd_serial);
			if (!curWnd)
			{
				ccd_record = ccd_record->next;
				continue;
			}
			curWnd->isExporting() = true;  // Qt 消息响应比较慢  提前置位
			post_event_mgr.Post([=]()
			{
				qApp->sendEvent(curWnd, ptcmd);
			});
			NotBlockingSleep(50);
			ccd_record = ccd_record->next;
			cmds.push_back(std::make_tuple(cmd.device_id,cmd.ccd_serial));
		}

		post_event_mgr.Post([this, record_id]()
		{
			QDateTime dt = QDateTime::fromTime_t(record_id->start_time);
			QString stritem = QString::fromWCharArray(record_id->task_name)
				+ dt.toString("-yy/MM/dd hh:mm:ss");
				
			for (int i = 0; i < ui.listw_exp->count(); i++)
			{
				if (ui.listw_exp->item(i)->text() ==  stritem)
				{
					QListWidgetItem* item = ui.listw_exp->takeItem(i);
					delete item;
					break;
				}
			}

			ui.currentExportRecord->setText(stritem.append(" is exporting ..."));
		});

		NotBlockingSleep(50);

		bool wait = false;
		for (;;)  // 等待单条导出结束 [4/10/2017 ejitec]
		{
			wait = false;
			for (auto it = cmds.begin(); it != cmds.end(); it++)
			{
				QDisPlayWidget* curWnd = g_theApp->getPlayWndBy(std::get<0>(*it), std::get<1>(*it));;
				if (curWnd && curWnd->isExporting())
				{
					wait = true;
					break;
				}
			}
			if (!wait || _ctx.cancel_export)
				break;
			NotBlockingSleep(1000);
		}

		if (_ctx.cancel_export && wait == true)  // 中途取消时  主动发送结束消息
		{
			for (auto it = cmds.begin(); it != cmds.end(); it++)
			{
				QDisPlayWidget* curWnd = g_theApp->getPlayWndBy(std::get<0>(*it), std::get<1>(*it));
				
				if (curWnd)
				{
					post_event_mgr.Post([=]()
					{
						qApp->sendEvent(curWnd, new MessageCmd(GT_CMD_EXPORT_CANCLE));
					});
				}
			}
			
			NotBlockingSleep(1000);
		}
			
		if (_ctx.cancel_export)
		{
			break;
		}

		_ctx.exported_records.push_back((EagleData_Record_Id*)exporting_record);
		post_event_mgr.Post([this, record_id]()
		{
			QDateTime dt = QDateTime::fromTime_t(record_id->start_time);
			ui.listw_done->addItem(QString::fromWCharArray(record_id->task_name)
				+ dt.toString("-yy/MM/dd hh:mm:ss"));
		});
	}  // end forever

	post_event_mgr.Post([this]()
	{
		ui.currentExportRecord->setText(QString("").sprintf("%d records export", (int)_ctx.exported_records.size()));
		ui.btn_start->setEnabled(true);
		ui.btn_delAll->setEnabled(true);
		ui.btn_delSel->setEnabled(true);
	});
}

void batchExport::on_startBatchExp()
{
	_ctx.export_path = ui.lineEditPath->text().trimmed();
	_ctx.export_type = ui.comboBox->currentIndex();
	QDir d;
	d.mkpath(_ctx.export_path);
	if (_ctx.export_path.isEmpty() || !QDir(_ctx.export_path).exists())
	{
		QMessageBox::warning(this, GetMessageBoxTitle(),tr("请选择导出目录"));
		return;
	}

	ui.currentExportRecord->setText(QString("").sprintf("%d records to export, now mounting disks", (int)_ctx.remain_export_record.size()));
	ui.btn_delAll->setEnabled(false);
	ui.btn_delSel->setEnabled(false);
	ui.btn_start->setEnabled(false);
	ui.listw_exp->setEnabled(false);
	QtConcurrent::run(this, &batchExport::StartBatchExportThread); // 线程属性
}
